// java/com/dbms/common/Column.java
package com.dbms.common;

import java.io.Serializable;

/**
 * 数据库表中「列」的元数据封装类。
 * 用于存储列的核心属性（名称、数据类型、长度约束、主键标识），并提供类型安全的构造逻辑，
 * 避免非法参数（如VARCHAR长度为负、类型与构造函数不匹配）导致的元数据异常。
 * 实现Serializable接口，支持列元数据的持久化存储或跨组件传输。
 */
public class Column implements Serializable {
    // 列的名称（如"id"、"username"），在表内唯一
    private final String columnName;
    // 列的数据类型（枚举Type，如INTEGER、VARCHAR）
    private final Type columnType;
    // VARCHAR类型专属：列的最大长度（如VARCHAR(32)中的32）；INTEGER类型此值固定为0
    private final int varcharLength;
    // 标记该列是否为主键（主键需满足唯一、非空约束）
    private final boolean isPrimaryKey;

    // ----- 私有构造函数：所有公共构造函数的统一入口，负责核心初始化与基础校验 -----
    /**
     * 列对象的底层构造入口，初始化所有成员变量并执行通用校验。
     * 所有公共构造函数需通过此方法创建实例，确保校验逻辑统一，避免重复代码。
     *
     * @param columnName 列的名称，非null且在表内唯一（由上层逻辑保证唯一性）
     * @param columnType 列的数据类型（Type枚举实例）
     * @param varcharLength VARCHAR类型的最大长度；INTEGER类型需传0
     * @param isPrimaryKey 是否为主键的标识
     * @throws IllegalArgumentException 若为VARCHAR类型但长度≤0，抛出此异常
     */
    public Column(String columnName, Type columnType, int varcharLength, boolean isPrimaryKey) {
        // 校验：VARCHAR类型必须指定正整数长度（避免无效长度如0或负数）
        if (columnType == Type.VARCHAR && varcharLength <= 0) {
            throw new IllegalArgumentException("VARCHAR length must be positive.");
        }
        this.columnName = columnName;
        this.columnType = columnType;
        this.varcharLength = varcharLength;
        this.isPrimaryKey = isPrimaryKey;
    }

    // ----- 公共构造函数：为不同场景提供清晰、类型安全的创建方式，降低使用成本 -----

    /**
     * 构造「INTEGER类型的非主键列」（最常用的基础整数列场景）。
     * 限定仅支持INTEGER类型，避免误用于其他类型（如VARCHAR）。
     *
     * @param columnName 列的名称（如"age"、"score"）
     * @param columnType 必须为Type.INTEGER，否则抛出异常
     * @throws IllegalArgumentException 若columnType不是INTEGER，抛出此异常
     */
    public Column(String columnName, Type columnType) {
        // 调用统一入口构造，INTEGER类型默认长度0、非主键
        this(columnName, columnType, 0, false);
        // 额外校验：此构造函数仅服务于INTEGER类型，防止误用
        if (columnType != Type.INTEGER) {
            throw new IllegalArgumentException("This constructor is for INTEGER type only. Use the constructor with length for VARCHAR.");
        }
    }

    /**
     * 构造「VARCHAR类型的非主键列」（字符串列场景，需指定长度约束）。
     * 限定仅支持VARCHAR类型，避免误用于INTEGER类型。
     *
     * @param columnName 列的名称（如"username"、"email"）
     * @param columnType 必须为Type.VARCHAR，否则抛出异常
     * @param length VARCHAR类型的最大长度（如32、64，需为正整数）
     * @throws IllegalArgumentException 若columnType不是VARCHAR，或length≤0（由底层构造函数校验），抛出此异常
     */
    public Column(String columnName, Type columnType, int length) {
        // 调用统一入口构造，VARCHAR类型需传长度、非主键
        this(columnName, columnType, length, false);
        // 额外校验：此构造函数仅服务于VARCHAR类型，防止误用
        if (columnType != Type.VARCHAR) {
            throw new IllegalArgumentException("This constructor is for VARCHAR type only.");
        }
    }

    /**
     * 构造「INTEGER类型的主键列」（表的唯一标识列场景，如id）。
     * 限定仅支持INTEGER主键（符合多数数据库主键设计习惯），避免非整数主键误用。
     *
     * @param columnName 列的名称（通常为"id"）
     * @param columnType 必须为Type.INTEGER，否则抛出异常
     * @param isPrimaryKey 主键标识（建议传true，传false无意义但不报错，由上层逻辑控制）
     * @throws IllegalArgumentException 若columnType不是INTEGER，抛出此异常
     */
    public Column(String columnName, Type columnType, boolean isPrimaryKey) {
        // 调用统一入口构造，INTEGER类型默认长度0、指定主键标识
        this(columnName, columnType, 0, isPrimaryKey);
        // 额外校验：此构造函数仅服务于INTEGER主键，防止非整数主键误用
        if (columnType != Type.INTEGER) {
            throw new IllegalArgumentException("This constructor is for INTEGER PRIMARY KEY type only.");
        }
    }

    // --- Getter方法：提供成员变量的只读访问（成员变量为final，确保元数据不可篡改） ---
    /**
     * 获取列的名称。
     * @return 列名（如"id"、"username"）
     */
    public String getColumnName() { return columnName; }

    /**
     * 获取列的数据类型。
     * @return 类型枚举实例（Type.INTEGER 或 Type.VARCHAR）
     */
    public Type getColumnType() { return columnType; }

    /**
     * 获取VARCHAR类型的最大长度（INTEGER类型返回0）。
     * @return VARCHAR长度（正整数）或0（INTEGER类型）
     */
    public int getVarcharLength() { return varcharLength; }

    /**
     * 判断列是否为主键。
     * @return true：主键列；false：非主键列
     */
    public boolean isPrimaryKey() { return isPrimaryKey; }
}